package com.laobiao.file_netty_lib.netty.client.handler;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.laobiao.file_netty_lib.content.LoggerUtil;
import com.laobiao.file_netty_lib.exception.FileBaseException;
import com.laobiao.file_netty_lib.netty.client.ClientBusiness;
import com.laobiao.file_netty_lib.packet.BasePacket;
import com.laobiao.file_netty_lib.packet.PacketType;
import com.laobiao.file_netty_lib.packet.command.ResoultCommand;
import com.laobiao.file_netty_lib.packet.command.download.ClientFileDownloadCommand;
import com.laobiao.file_netty_lib.packet.command.download.ServerFileDownloadResoutCommand;
import com.laobiao.file_netty_lib.packet.data.BaseDataPacket;
import com.laobiao.file_netty_lib.util.CheckCodeUtil;

import io.netty.channel.Channel;

/**
 * 文件下载业务处理类
 * 
 * @author 38079
 *
 */

public class ClientFileDownloadBusiness implements ClientBusiness {
	private final Logger logger = LoggerUtil.getLogger(ClientFileDownloadBusiness.class);

	/**
	 * 客户端下载命令内容
	 */
	private ClientFileDownloadCommand fileDownloadCommand;
	/**
	 * 服务端反馈文件详情内容
	 */
	private ServerFileDownloadResoutCommand fileDownloadResoultCommand;
	/**
	 * 连接
	 */
	private Channel channel;

	/**
	 * 当前等待时间
	 */
	private volatile long currMillisecond = 20000;
	/**
	 * 执行超时时间
	 */
	private int timeOutSeconds = 20;

	/**
	 * 下载到本地的文件
	 */
	private File downloadLocalFile;
	/**
	 * 写文件对象
	 */
	private RandomAccessFile write;
	

	/**
	 * 整个流程是否停止，异常或正常上传完成后置true
	 */
	private volatile boolean stop = false;

	/**
	 * 是否上传成功，流程完成且正常上传成功是置true
	 */
	private volatile boolean download = false;

	/**
	 * 服务端反馈的消息
	 */
	private String msg = "";
	
	private long startTime;

	public ClientFileDownloadBusiness() {
	}

	public ClientFileDownloadBusiness(String downloadLocalFilePah, ClientFileDownloadCommand fileDownloadCommand,
			Channel channel) {
		this.channel = channel;
		this.fileDownloadCommand = fileDownloadCommand;
		if (downloadLocalFilePah == null) {
			throw new FileBaseException("下载到本地的文件路径不能为空！", FileBaseException.ERR_PARAM_NULL);
		}
		this.downloadLocalFile = new File(downloadLocalFilePah);
		try {
			if (!this.downloadLocalFile.exists() || !this.downloadLocalFile.isFile()) {
				File parent = this.downloadLocalFile.getParentFile();
				if (!parent.exists() || !parent.isDirectory()) {
					parent.mkdirs();
				}
				this.downloadLocalFile.createNewFile();
			}
		} catch (Exception e) {
			err(e.getMessage());
			throw new FileBaseException("文件创建错误!", e, FileBaseException.ERR_PARAM_WRONG);
		}
		try {
			write = new RandomAccessFile(downloadLocalFile, "rw");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			err(e.getMessage());
			throw new FileBaseException("文件创建错误!", e, FileBaseException.ERR_PARAM_WRONG);
		}
	}

	public ClientFileDownloadCommand getFileDownloadCommand() {
		return fileDownloadCommand;
	}

	public void setFileDownloadCommand(ClientFileDownloadCommand fileDownloadCommand) {
		this.fileDownloadCommand = fileDownloadCommand;
	}

	public ServerFileDownloadResoutCommand getFileDownloadResoultCommand() {
		return fileDownloadResoultCommand;
	}

	public void setFileDownloadResoultCommand(ServerFileDownloadResoutCommand fileDownloadResoultCommand) {
		this.fileDownloadResoultCommand = fileDownloadResoultCommand;
	}


	@Override
	public void resoultPacket(BasePacket packet) {
		if (packet.getPacketType() == PacketType.COMMAND) {
			if (packet instanceof ServerFileDownloadResoutCommand) {// 要下载的文件详情信息
				this.fileDownloadResoultCommand = (ServerFileDownloadResoutCommand) packet;
				logger.config("远程文件【"+fileDownloadCommand.getRemoteFilePath()+"】开始下载！");
				startTime=System.currentTimeMillis();
				reflushCurrMillisecond();
			} else if (packet instanceof ResoultCommand) {
				ResoultCommand resoultCommand = (ResoultCommand) packet;
				if (!resoultCommand.isStatus()) {
					err(resoultCommand.getMessage());
					logger.warning(resoultCommand.getMessage());
					close();
				} else {
					if (resoultCommand.getCode() == ResoultCommand.ResoultCode.Common.SERVER_PUSHFILE) {// 服务端文件发送成功
						//进入校验阶段
						close();
						if(Arrays.equals(CheckCodeUtil.getCheckCode(downloadLocalFile),fileDownloadResoultCommand.getCheckCode())) {
							long sendSeconde=(System.currentTimeMillis()-startTime)/1000;
							sucess(resoultCommand.getMessage());
							logger.info("远程文件【"+fileDownloadCommand.getRemoteFilePath()+"】下载成功:\n\r    用时:"+sendSeconde+"秒,速度:"+(fileDownloadResoultCommand.getFileSize()/1024.000/sendSeconde)+"KB/秒");
						}else {
							err("本地文件校验失败！");
							logger.log(Level.WARNING, "本地文件校验失败！");
//							ResoultCommand reCommad = new ResoultCommand(ResoultCommand.ResoultCode.Common.CLIENT_CHECK,
//									"文件校验失败！", false, fileDownloadCommand.getBusinessGroup());
//							channel.writeAndFlush(reCommad);
						}
						
					}else {
						//其他反馈命令类型全部不管
						reflushCurrMillisecond();
					}
					
				}
			}
		}else if(packet.getPacketType() == PacketType.DATA) {
			if(packet instanceof BaseDataPacket) {
				BaseDataPacket dataPacket=(BaseDataPacket)packet;
				try {
					write.write(dataPacket.getContent());
					reflushCurrMillisecond();//更新等待时间
				} catch (IOException e) {
					// TODO Auto-generated catch block
					err("本地文件写入失败！"+e.getMessage());
					logger.log(Level.WARNING, "本地文件写入失败！", e);
					close();
					ResoultCommand reCommad = new ResoultCommand(ResoultCommand.ResoultCode.Download.CLIENT_DOWNLOAD,
							"客户端错误！" + e.getMessage(), false, fileDownloadCommand.getBusinessGroup());
					channel.writeAndFlush(reCommad);
				}
			}
		}

	}

	@Override
	public Object executStatus(int executReturnTimeOutSeconds) {
		channel.writeAndFlush(fileDownloadCommand);
		return isDownload(executReturnTimeOutSeconds);
	}

	/**
	 * 写入远端错误消息
	 * 
	 * @param msg
	 */
	private void err(String msg) {
		setStatus(true, false, msg);
	}

	/**
	 * 执行成功
	 * 
	 * @param msg
	 */
	private void sucess(String msg) {
		setStatus(true, true, msg);
	}

	private void setStatus(boolean stop, boolean download, String msg) {
		this.stop = stop;
		this.download = download;
		this.msg = msg;
		if (stop) {// 停止
			close();
		}
	}
	/**
	 * 更新超时等待时间
	 */
	private void reflushCurrMillisecond() {
		currMillisecond = timeOutSeconds * 1000;
	}

	/**
	 * 检测是否下载成功
	 * 
	 * @param timeOutSeconds 超时时间
	 * @return
	 */
	public boolean isDownload(int timeOutSeconds) {
		this.timeOutSeconds = timeOutSeconds;
		long defaultSleepTime = 100;
		currMillisecond = timeOutSeconds * 1000;
		while (!stop && currMillisecond > 0) {
			currMillisecond -= defaultSleepTime;
			try {
				Thread.currentThread().sleep(defaultSleepTime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		if (!stop) {
			throw new FileBaseException("上传下载超时！", FileBaseException.ERR_PARAM_WRONG);
		}
		return download;
	}

	@Override
	public void close() {
		// TODO Auto-generated method stub
		try {
			write.close();
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

	@Override
	public Channel getChannel() {
		return channel;
	}

}
